package io.noties.markwon.theme

import androidx.compose.ui.text.font.FontFamily
import com.gitee.wsl.common.ui.theme.*
import com.gitee.wsl.common.ui.theme.merge
import com.gitee.wsl.store.StoreServer
import com.squareup.moshi.JsonClass


interface MarkdwonColorPaletteScheme:SubColorPaletteScheme {
    //link
    var linkColor:Long

    var blockQuoteColor:Long

    //list
    var listItemColor:Long

    /**
     * code
     */
    var codeTextColor:Long
    var codeBlockTextColor:Long
    var codeBackgroundColor:Long
    var codeBlockBackgroundColor:Long

    var headingBreakColor:Long
    var thematicBreakColor:Long
    var headingColor:Long

    //tasklist style
    var checkedFillColor :Long
    var normalOutlineColor :Long
    var checkMarkColor:Long


    /**
     * table style
     */
    // by default paint.color * TABLE_BORDER_DEF_ALPHA
    var tableBorderColor :Long
    // by default paint.color * TABLE_ODD_ROW_DEF_ALPHA
    var tableOddRowBackgroundColor :Long
    // @since 1.1.1
    // by default no background
    var tableEvenRowBackgroundColor :Long
    // @since 1.1.1
    // by default no background
    var tableHeaderRowBackgroundColor :Long
}

@JsonClass(generateAdapter = true)
data class MarkdwonColorSchemeStoreBean(
    var linkColor:Long?=null,
    var blockQuoteColor:Long?=null,
    var listItemColor:Long?=null,
    var codeTextColor:Long?=null,
    var codeBlockTextColor:Long?=null,
    var codeBackgroundColor:Long?=null,
    var codeBlockBackgroundColor:Long?=null,
    var headingBreakColor:Long?=null,
    var thematicBreakColor:Long?=null,
    var headingColor:Long?=null,

    //tasklist style
    var checkedFillColor :Long?=null,
    var normalOutlineColor :Long?=null,
    var checkMarkColor:Long?=null,

    /**
     * table style
     */
    // by default paint.color * TABLE_BORDER_DEF_ALPHA
    var tableBorderColor :Long?=null,
    // by default paint.color * TABLE_ODD_ROW_DEF_ALPHA
    var tableOddRowBackgroundColor :Long?=null,
    // @since 1.1.1
    // by default no background
    var tableEvenRowBackgroundColor :Long?=null,
    // @since 1.1.1
    // by default no background
    var tableHeaderRowBackgroundColor :Long?=null
)

class MarkdwonColorThemeImp(basePalette:()-> com.gitee.wsl.common.ui.theme.ColorPaletteScheme): com.gitee.wsl.common.ui.theme.SubColorSchemeImp(basePalette),MarkdwonColorPaletteScheme{

    val STORE_MARKDON_LABEL = STORE_LABEL+"_markdon_"

    var markdonStoreBean = MarkdwonColorSchemeStoreBean()

    override fun saveToStore(server: StoreServer) {
        super.saveToStore(server)
        server.putPreference(STORE_MARKDON_LABEL,markdonStoreBean)
    }

    override fun reStore(server: StoreServer) {
        super.reStore(server)
        server.getPreference(STORE_MARKDON_LABEL,markdonStoreBean)?.let {
            markdonStoreBean=it
        }
    }

    override var linkColor: Long by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.linkColor
    ) {
        basePalette().urls
    }

    override var blockQuoteColor: Long by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.blockQuoteColor
    ) {
        basePalette().background
    }
    override var listItemColor: Long by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.listItemColor
    ) {
        basePalette().flamingo
    }
    override var codeTextColor: Long by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.codeTextColor
    ) {
        basePalette().mark2Text
    }
    override var codeBlockTextColor: Long by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.codeBlockTextColor
    ) {
        basePalette().mark2Text
    }
    override var codeBackgroundColor: Long by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.codeBackgroundColor
    ) {
        basePalette().background
    }
    override var codeBlockBackgroundColor: Long by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.codeBlockBackgroundColor
    ) {
        basePalette().background
    }
    override var headingBreakColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.headingBreakColor
    ) {
        basePalette().subtext0
    }
    override var thematicBreakColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.thematicBreakColor
    ) {
        basePalette().boldColor3
    }

    override var headingColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.headingColor
    ) {
        basePalette().subtext1
    }

    override var checkedFillColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.checkedFillColor
    ) {
        basePalette().green
    }
    override var normalOutlineColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.normalOutlineColor
    ) {
        basePalette().boldColor1
    }
    override var checkMarkColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.checkMarkColor
    ) {
        basePalette().mark2Text
    }
    override var tableBorderColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.tableBorderColor
    ) {
        basePalette().boldColor3
    }
    override var tableOddRowBackgroundColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.tableOddRowBackgroundColor
    ) {
        basePalette().surface0
    }
    override var tableEvenRowBackgroundColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.tableEvenRowBackgroundColor
    ) {
        basePalette().surface1
    }
    override var tableHeaderRowBackgroundColor: Long  by com.gitee.wsl.common.ui.theme.SubColorPaletteSaveAbleProp(
        markdonStoreBean.tableHeaderRowBackgroundColor
    ) {
        basePalette().surface2
    }
}

@JsonClass(generateAdapter = true)
data class MarkdwonTypographyCacheBean(

    var isLinkUnderlined:Boolean? = null,

    var blockMargin:Int? = null,
    var blockQuoteWidth:Int? = null,

    var bulletListItemStrokeWidth:Int? = null,
    var bulletWidth:Int? = null,

    var bulletPointWidth:Int? = null,

    //sub script
    var scriptDefTextSizeRatio:Float?=null,

    /**
     * code
     */
    var codeTextSize:Int? = null,
    var codeTypeface:String? = null,

    var codeBlockMargin:Int? = null,
    var codeBlockTypeface:String ? = null,// @since 3.0.0
    var codeBlockTextSize:Int? = null,// @since 3.0.0

    var headingBreakHeight :Int? = null,
    var headingTypeface:String? = null,
    var headingTextSizeMultipliers:FloatArray? = null,

    var thematicBreakHeight :Int? = null,

    // table Style
    var tableCellPadding :Int ? = null,

    var tableBorderWidth :Int ? = null

) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as MarkdwonTypographyCacheBean

        if (isLinkUnderlined != other.isLinkUnderlined) return false
        if (blockMargin != other.blockMargin) return false
        if (blockQuoteWidth != other.blockQuoteWidth) return false
        if (bulletListItemStrokeWidth != other.bulletListItemStrokeWidth) return false
        if (bulletWidth != other.bulletWidth) return false
        if (bulletPointWidth != other.bulletPointWidth) return false
        if (codeTextSize != other.codeTextSize) return false
        if (codeTypeface != other.codeTypeface) return false
        if (codeBlockMargin != other.codeBlockMargin) return false
        if (codeBlockTypeface != other.codeBlockTypeface) return false
        if (codeBlockTextSize != other.codeBlockTextSize) return false
        if (headingBreakHeight != other.headingBreakHeight) return false
        if (headingTypeface != other.headingTypeface) return false
        if (headingTextSizeMultipliers != null) {
            if (other.headingTextSizeMultipliers == null) return false
            if (!headingTextSizeMultipliers.contentEquals(other.headingTextSizeMultipliers)) return false
        } else if (other.headingTextSizeMultipliers != null) return false
        if (thematicBreakHeight != other.thematicBreakHeight) return false

        return true
    }

    override fun hashCode(): Int {
        var result = isLinkUnderlined?.hashCode() ?: 0
        result = 31 * result + (blockMargin ?: 0)
        result = 31 * result + (blockQuoteWidth ?: 0)
        result = 31 * result + (bulletListItemStrokeWidth ?: 0)
        result = 31 * result + (bulletWidth ?: 0)
        result = 31 * result + (bulletPointWidth ?: 0)
        result = 31 * result + (codeTextSize ?: 0)
        result = 31 * result + (codeTypeface?.hashCode() ?: 0)
        result = 31 * result + (codeBlockMargin ?: 0)
        result = 31 * result + (codeBlockTypeface?.hashCode() ?: 0)
        result = 31 * result + (codeBlockTextSize ?: 0)
        result = 31 * result + (headingBreakHeight ?: 0)
        result = 31 * result + (headingTypeface?.hashCode() ?: 0)
        result = 31 * result + (headingTextSizeMultipliers?.contentHashCode() ?: 0)
        result = 31 * result + (thematicBreakHeight ?: 0)
        return result
    }
}

interface MarkdwonTypography{
    var isLinkUnderlined:Boolean

    var blockMargin:Int
    var blockQuoteWidth:Int

    var bulletListItemStrokeWidth:Int
    var bulletWidth:Int

    var bulletPointWidth:Int


    var scriptDefTextSizeRatio:Float

    //code
    var codeTextSize:Int
    var codeTypeface:String

    var codeBlockMargin:Int
    var codeBlockTypeface:String // @since 3.0.0
    var codeBlockTextSize:Int// @since 3.0.0

    var headingBreakHeight :Int
    var headingTypeface:String
    var headingTextSizeMultipliers:FloatArray

    var thematicBreakHeight :Int

    // table Style
    var tableCellPadding :Int

    var tableBorderWidth :Int


}

data class MarkdwonTypographyBean(
    override var isLinkUnderlined:Boolean,

    override var blockMargin:Int,
    override var blockQuoteWidth:Int,

    override var bulletListItemStrokeWidth:Int,
    override var bulletWidth:Int,

    override var bulletPointWidth:Int,

    override var scriptDefTextSizeRatio: Float,

    override var codeTextSize:Int,
    override var codeTypeface:String,

    override var codeBlockMargin:Int,
    override var codeBlockTypeface:String,// @since 3.0.0
    override var codeBlockTextSize:Int,// @since 3.0.0

    override var headingBreakHeight :Int,
    override var headingTypeface:String,
    override var headingTextSizeMultipliers:FloatArray,

    override var thematicBreakHeight :Int,

    override var tableCellPadding :Int,
    override var tableBorderWidth :Int
):MarkdwonTypography{
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as MarkdwonTypographyBean

        if (isLinkUnderlined != other.isLinkUnderlined) return false
        if (blockMargin != other.blockMargin) return false
        if (blockQuoteWidth != other.blockQuoteWidth) return false
        if (bulletListItemStrokeWidth != other.bulletListItemStrokeWidth) return false
        if (bulletWidth != other.bulletWidth) return false
        if (bulletPointWidth != other.bulletPointWidth) return false
        if (codeTextSize != other.codeTextSize) return false
        if (codeTypeface != other.codeTypeface) return false
        if (codeBlockMargin != other.codeBlockMargin) return false
        if (codeBlockTypeface != other.codeBlockTypeface) return false
        if (codeBlockTextSize != other.codeBlockTextSize) return false
        if (headingBreakHeight != other.headingBreakHeight) return false
        if (headingTypeface != other.headingTypeface) return false
        if (!headingTextSizeMultipliers.contentEquals(other.headingTextSizeMultipliers)) return false
        if (thematicBreakHeight != other.thematicBreakHeight) return false

        return true
    }

    override fun hashCode(): Int {
        var result = isLinkUnderlined.hashCode()
        result = 31 * result + blockMargin
        result = 31 * result + blockQuoteWidth
        result = 31 * result + bulletListItemStrokeWidth
        result = 31 * result + bulletWidth
        result = 31 * result + bulletPointWidth
        result = 31 * result + codeTextSize
        result = 31 * result + codeTypeface.hashCode()
        result = 31 * result + codeBlockMargin
        result = 31 * result + codeBlockTypeface.hashCode()
        result = 31 * result + codeBlockTextSize
        result = 31 * result + headingBreakHeight
        result = 31 * result + headingTypeface.hashCode()
        result = 31 * result + headingTextSizeMultipliers.contentHashCode()
        result = 31 * result + thematicBreakHeight
        return result
    }

}

val defaultMarkdwonTypography by lazy{
    MarkdwonTypographyBean(
        isLinkUnderlined=true,
        blockMargin=24,
        blockQuoteWidth=4,
        bulletListItemStrokeWidth=1,
        bulletWidth=0,
        bulletPointWidth=0,
        scriptDefTextSizeRatio = SCRIPT_DEF_TEXT_SIZE_RATIO,
        codeTextSize=0,
        codeTypeface= FontFamily.Monospace.name,
        codeBlockMargin=8,
        codeBlockTypeface= FontFamily.Monospace.name,
        codeBlockTextSize=0,
        headingBreakHeight=1,
        headingTypeface="",
        headingTextSizeMultipliers=floatArrayOf(1.45f, 1.35f, 1.25f, 1.15f, 1.1f, 1.05f),
        thematicBreakHeight=4,
        tableCellPadding=0,
        tableBorderWidth=0
    )
}

const val SCRIPT_DEF_TEXT_SIZE_RATIO = .75f

class MarkwonTypographyImp(val colorTheme:MarkdwonColorPaletteScheme, base: () -> com.gitee.wsl.common.ui.theme.TypographyScheme):
    com.gitee.wsl.common.ui.theme.SubTypography(base),MarkdwonTypography{
    val STORE_MARKDON_TYPOGRAPHY_LABEL = STORE_TYPOGRAPHY_LABEL +"_markwon"

    var defaultTypography:MarkdwonTypography= defaultMarkdwonTypography

    var cacheTypography = MarkdwonTypographyCacheBean()

    var bodyText = body1.merge{
        this.fontFamily= FontFamily.Default
    }

    var codeBlock = bodySmall.merge{
        this.fontFamily= FontFamily.Monospace
    }

    override var isLinkUnderlined by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.isLinkUnderlined
    ) { defaultTypography.isLinkUnderlined }

    override var blockMargin: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.blockMargin
    ) { defaultTypography.blockMargin }
    override var blockQuoteWidth: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.blockQuoteWidth
    ) { defaultTypography.blockQuoteWidth }

    override var bulletListItemStrokeWidth: Int  by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.bulletListItemStrokeWidth
    ) { defaultTypography.bulletListItemStrokeWidth }
    override var bulletWidth: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.bulletWidth
    ) { defaultTypography.bulletWidth }
    override var bulletPointWidth: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.bulletPointWidth
    ) { defaultTypography.bulletPointWidth }

    override var scriptDefTextSizeRatio: Float by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.scriptDefTextSizeRatio
    ) { defaultTypography.scriptDefTextSizeRatio }

    override var codeTextSize: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.codeTextSize
    ) { defaultTypography.codeTextSize }
    override var codeTypeface: String by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.codeTypeface
    ) { defaultTypography.codeTypeface }
    override var codeBlockMargin: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.codeBlockMargin
    ) { defaultTypography.codeBlockMargin }
    override var codeBlockTypeface: String by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.codeBlockTypeface
    ) { defaultTypography.codeBlockTypeface }
    override var codeBlockTextSize: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.codeBlockTextSize
    ) { defaultTypography.codeBlockTextSize }

    override var headingBreakHeight: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.headingBreakHeight
    ) { defaultTypography.headingBreakHeight }
    override var headingTypeface: String by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.headingTypeface
    ) { defaultTypography.headingTypeface }
    override var headingTextSizeMultipliers: FloatArray by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.headingTextSizeMultipliers
    ) { defaultTypography.headingTextSizeMultipliers }

    override var thematicBreakHeight: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.thematicBreakHeight
    ) { defaultTypography.thematicBreakHeight }

    override var tableCellPadding: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.tableCellPadding
    ) { defaultTypography.tableCellPadding }
    override var tableBorderWidth: Int by com.gitee.wsl.common.ui.theme.SubTypographySaveAbleProp(
        cacheTypography.tableBorderWidth
    ) { defaultTypography.tableBorderWidth }

}

typealias MarkwonThemeCustomHandler = SubThemeScope<MarkdwonColorPaletteScheme, MarkwonTypographyImp>.()->Unit

class MarkwonTheme(parentTheme: DefaultTheme, val colorTheme:MarkdwonColorPaletteScheme = MarkdwonColorThemeImp() { parentTheme.colorScheme }):
    SubThemeOnDefault<MarkdwonColorPaletteScheme, MarkwonTypographyImp>(
        parentTheme,
        colorTheme,
        MarkwonTypographyImp(colorTheme) { parentTheme.typography }){
}

class MarkwonCategoryTheme(markwonTheme: MarkwonTheme):SubCategoryTheme<com.gitee.wsl.common.ui.theme.ColorPaletteScheme, com.gitee.wsl.common.ui.theme.TypographyScheme,MarkdwonColorPaletteScheme, MarkwonTypographyImp,MarkwonTheme>(markwonTheme)

fun markwonTheme(parentTheme: DefaultTheme, colorTheme:MarkdwonColorPaletteScheme = MarkdwonColorThemeImp() { parentTheme.colorScheme },config:CategoryThemeScope<MarkdwonColorPaletteScheme,MarkwonTypographyImp>.()->Unit):MarkwonCategoryTheme{
    val markwonCategoryTheme=MarkwonCategoryTheme(MarkwonTheme(parentTheme,colorTheme))
    config(markwonCategoryTheme)
    return markwonCategoryTheme
}

